#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include "gam_fork.h"
#include "gam_error.h"

int gamin_fork_server( const char *fam_client_id ) {
  const char *server_path = "/bin";
  int ret, pid, status;
  if( !server_path ) {
    gam_error( DEBUG_INFO, "找不到 gam_server\n" );
  }
  GAM_DEBUG( DEBUG_INFO, "要求 %s 发送客户端ID %s\n", server_path, fam_client_id );
  pid = fork();
  if( pid == 0 ) {
    int fd;
    long open_max;
    long i;
    open_max = sysconf( _SC_OPEN_MAX );
    for( i = 0; i < open_max; i++ ) {
      fcntl( i, F_SETFD, FD_CLOEXEC );
    }
    fd = open( "/dev/null", O_RDONLY );
    if( fd != -1 ) {
      dup2( fd, 0 );
      close( fd );
    }
    fd = open( "/dev/null", O_WRONLY );
    if( fd != -1 ) {
      dup2( fd, 1 );
      dup2( fd, 2 );
      close( fd );
    }
    setsid();
    if( fork() == 0 ) {
      #ifdef HAVE_SETENV
      setenv( "GAM_CLIENT_ID", fam_client_id, 0 );
      #elif HAVE_PUTENV
      char *client_id = malloc( strlen( fam_client_id ) + sizeof "GAM_CLIENT_ID=" );
      if( client_id ) {
        strcpy( client_id, "GAM_CLIENT_ID=" );
        strcat( client_id, fam_client_id );
        putenv( client_id );
      }
      #endif /* HAVE_SETENV */
      execl( server_path, server_path, NULL );
      gam_error( DEBUG_INFO, "failed to exec %s\n", server_path );
    }
    _exit( 0 );
  }
retry_wait:
  ret = waitpid( pid, &status, 0 );
  if( ret < 0 ) {
    if( errno == EINTR ) {
      goto retry_wait;
    }
  }
  return ( 0 );
}
